﻿using DHISInteroperability.Authentication;
using DHISInteroperability.DataTransfer;
using DHISInteroperability.Resources;
using DHISInteroperability.SystemInformation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Xml.XPath;

namespace DHISInteroperability
{
    public class DataTransferManager
    {     
        //private AuthorizationAgent authorizationAgent;
        private string baseUrl;
        private string authorizationText;

        public DataTransferManager(string baseUrl, AuthorizationAgent authorizationAgent)
        {
            this.baseUrl = baseUrl;
            //this.authorizationAgent = authorizationAgent;
            this.authorizationText = authorizationAgent.AuthorizationText;
        }

        public DataTransferManager(string baseUrl, string authorizationText)
        {
            this.baseUrl = baseUrl;
            this.authorizationText = authorizationText;
        }

        public importSummary SendDataValues(dataValueSet dataValueSet)
        {
            if (baseUrl.EndsWith("/")) baseUrl = baseUrl.Substring(0, baseUrl.Length - 1);
            string requestingUrl = string.Format("{0}{1}", baseUrl, DHIS2System.DATA_VALUES_POSTING_URL);

            string objectXML = GetXml(dataValueSet, typeof(dataValueSet));
            byte[] data = Encoding.Unicode.GetBytes(objectXML.ToCharArray());
            //byte[] data = ASCIIEncoding.ASCII.GetBytes();

            var httpRequest = WebRequest.Create(requestingUrl);
            httpRequest.Method = "POST";
            httpRequest.Headers[DHIS2System.AUTHORIZATION_HEADER] = authorizationText;
            httpRequest.ContentType = DHIS2System.DEFAULT_CONTENT_TYPE;
            httpRequest.ContentLength = data.Length;  
            
            var requestStream = httpRequest.GetRequestStream();
            requestStream.Write(data, 0, data.Length);
            requestStream.Close();

            var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
            importSummary outputObject = null;
            switch (httpResponse.StatusCode)
            {
                case HttpStatusCode.Created:
                case HttpStatusCode.OK:
                    var responseStream = httpResponse.GetResponseStream();
                    Encoding encode = Encoding.GetEncoding("utf-8");
                    StreamReader reader = new StreamReader(responseStream, encode);
                    string output = reader.ReadToEnd();
                    outputObject = GetObject(output, typeof(importSummary)) as importSummary;
                    break;
            }

            return outputObject;
        }

        public dataValueSet GetDataValues(string dataset, string organisationUnit, string period)
        {
            if (baseUrl.EndsWith("/")) baseUrl = baseUrl.Substring(0, baseUrl.Length - 1);
            string requestingUrl = string.Format("{0}{1}", baseUrl, DHIS2System.DATA_VALUES_POSTING_URL);

            string paramLinker = (requestingUrl.Contains("?")) ? "&" : "?";
            requestingUrl = string.Format("{0}{1}dataSet={2}&period={3}&orgUnit={4}",
                requestingUrl, paramLinker, dataset, period, organisationUnit);

            var httpRequest = WebRequest.Create(requestingUrl) as HttpWebRequest;
            httpRequest.Method = "GET";
            httpRequest.Headers[DHIS2System.AUTHORIZATION_HEADER] = authorizationText;
            httpRequest.Accept = "application/xml";

            var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
            dataValueSet outputObject = null;
            switch (httpResponse.StatusCode)
            {
                case HttpStatusCode.Created:
                case HttpStatusCode.OK:
                    var responseStream = httpResponse.GetResponseStream();
                    Encoding encode = Encoding.GetEncoding("utf-8");
                    StreamReader reader = new StreamReader(responseStream, encode);
                    string output = reader.ReadToEnd();
                    outputObject = GetObject(output, typeof(dataValueSet)) as dataValueSet;
                    break;
            }

            return outputObject;
        }

        public dataValueSet GetDataValues(List<string> datasets, List<string> organisationUnits, string startDate, string endDate, bool children = true)
        {
            if (baseUrl.EndsWith("/")) baseUrl = baseUrl.Substring(0, baseUrl.Length - 1);
            string requestingUrl = string.Format("{0}{1}", baseUrl, DHIS2System.DATA_VALUES_POSTING_URL);

            DateTime startDateTime = DateTime.Parse(startDate);
            DateTime endDateTime = DateTime.Parse(endDate);

            string paramLinker = (requestingUrl.Contains("?")) ? "&" : "?";
            requestingUrl = string.Format("{0}{1}startDate={2:yyyy-MM-dd}&endDate={3:yyyy-MM-dd}&children={4}",
                requestingUrl, paramLinker, startDateTime, endDateTime, children);

            StringBuilder sBuilder = new StringBuilder();
            sBuilder.Append(requestingUrl);
            // Inserting several organisation units
            foreach (var organisationUnit in organisationUnits)
            {
                string orgUnit = string.Format("&orgUnit={0}", organisationUnit);
                sBuilder.Append(orgUnit);
            }

            // Inserting several datasets
            foreach (var dataset in datasets)
            {
                string datasetQueryString = string.Format("&dataSet={0}", dataset);
                sBuilder.Append(datasetQueryString);
            }

            requestingUrl = sBuilder.ToString();

            var httpRequest = WebRequest.Create(requestingUrl) as HttpWebRequest;
            httpRequest.Method = "GET";
            httpRequest.Headers[DHIS2System.AUTHORIZATION_HEADER] = authorizationText;
            httpRequest.Accept = "application/xml";

            var response = httpRequest.GetResponse();
            var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
            dataValueSet outputObject = null;
            switch (httpResponse.StatusCode)
            {
                case HttpStatusCode.Created:
                case HttpStatusCode.OK:
                    var responseStream = httpResponse.GetResponseStream();
                    Encoding encode = Encoding.GetEncoding("utf-8");
                    StreamReader reader = new StreamReader(responseStream, encode);
                    string output = reader.ReadToEnd();
                    outputObject = GetObject(output, typeof(dataValueSet)) as dataValueSet;
                    break;
            }

            return outputObject;
        }

        public List<dataSet> GetAllDataSets()
        {
            if (baseUrl.EndsWith("/")) baseUrl = baseUrl.Substring(0, baseUrl.Length - 1);
            string requestingUrl = string.Format("{0}{1}", baseUrl, DHIS2System.DATASET_METADATA);

            var httpRequest = WebRequest.Create(requestingUrl) as HttpWebRequest;
            httpRequest.Method = "GET";
            httpRequest.Headers[DHIS2System.AUTHORIZATION_HEADER] = authorizationText;
            httpRequest.Accept = "application/xml";

            var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
            if (httpResponse.StatusCode == HttpStatusCode.OK)
            {
                var responseStream = httpResponse.GetResponseStream();
                Encoding encode = Encoding.GetEncoding("utf-8");
                StreamReader reader = new StreamReader(responseStream, encode);
                string output = reader.ReadToEnd();

                var metadata = GetObject(output, typeof(metadata)) as metadata;
                var results = metadata.dataSets.ToList();
                return results;
            }
            return null;
        }

        public dataSet GetDataSet(string id)
        {
            var dataset = GetDataSet(id, null);
            return dataset;

            //if (baseUrl.EndsWith("/")) baseUrl = baseUrl.Substring(0, baseUrl.Length - 1);
            //string requestingUrl = string.Format("{0}{1}/{2}", baseUrl, DHIS2System.DATASET_METADATA, id);

            //var httpRequest = WebRequest.Create(requestingUrl) as HttpWebRequest;
            //httpRequest.Method = "GET";
            //httpRequest.Headers[DHIS2System.AUTHORIZATION_HEADER] = authorizationAgent.AuthorizationText;
            //httpRequest.Accept = "application/xml";

            //var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
            //if (httpResponse.StatusCode == HttpStatusCode.OK)
            //{
            //    var responseStream = httpResponse.GetResponseStream();
            //    Encoding encode = Encoding.GetEncoding("utf-8");
            //    StreamReader reader = new StreamReader(responseStream, encode);
            //    string output = reader.ReadToEnd();

            //    var dataset = GetObject(output, typeof(dataSet)) as dataSet;
            //    return dataset;
            //}
            //return null;
        }

        public dataSet GetDataSet(string id, params string[] fields)
        {
            if (baseUrl.EndsWith("/")) baseUrl = baseUrl.Substring(0, baseUrl.Length - 1);
            string requestingUrl = string.Format("{0}{1}/{2}", baseUrl, DHIS2System.DATASET_METADATA, id);

            if (fields != null && fields.Length > 0)
            {
                string paramLinker = (requestingUrl.Contains("?")) ? "&" : "?";
                StringBuilder sBuilder = new StringBuilder();
                sBuilder.Append(requestingUrl);
                sBuilder.Append(paramLinker);
                sBuilder.Append("fields=");
                for (int i = 0; i < fields.Length; i++)
                {
                    string field = fields[i];
                    sBuilder.Append(field);
                    if ((i + 1) != fields.Length) sBuilder.Append(",");
                }
                requestingUrl = sBuilder.ToString();
            }

            var httpRequest = WebRequest.Create(requestingUrl) as HttpWebRequest;
            httpRequest.Method = "GET";
            httpRequest.Headers[DHIS2System.AUTHORIZATION_HEADER] = authorizationText;
            httpRequest.Accept = "application/xml";

            var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
            if (httpResponse.StatusCode == HttpStatusCode.OK)
            {
                var responseStream = httpResponse.GetResponseStream();
                Encoding encode = Encoding.GetEncoding("utf-8");
                StreamReader reader = new StreamReader(responseStream, encode);
                string output = reader.ReadToEnd();

                var dataset = GetObject(output, typeof(dataSet)) as dataSet;
                return dataset;
            }
            return null;
        }

        private string GetXml(object dataObject, Type objectType)
        {
            XmlSerializer serializer = new XmlSerializer(objectType);
            StringWriter stringWriter = new StringWriter();
            serializer.Serialize(stringWriter, dataObject);
            string output = stringWriter.ToString();
            return output;
        }

        private object GetObject(string xml, Type objectType)
        {
            XmlSerializer serializer = new XmlSerializer(objectType);
            var stringReader = new StringReader(xml);
            var obj = serializer.Deserialize(stringReader);
            return obj;
        }
    }
}
